home *** CD-ROM | disk | FTP | other *** search
/ EnigmA Amiga Run 1995 October / EnigmA AMIGA RUN 01 (1995)(G.R. Edizioni)(IT)[!][issue 1995-10][Aminet 7].iso / Aminet / dev / gcc / ixemul_src.lha / ixemul-41.0 / stdio_2 / vfprintf.c < prev    next >
C/C++ Source or Header  |  1995-05-17  |  23KB  |  996 lines

  1. /*-
  2.  * Copyright (c) 1990 The Regents of the University of California.
  3.  * All rights reserved.
  4.  *
  5.  * This code is derived from software contributed to Berkeley by
  6.  * Chris Torek.
  7.  *
  8.  * Redistribution and use in source and binary forms, with or without
  9.  * modification, are permitted provided that the following conditions
  10.  * are met:
  11.  * 1. Redistributions of source code must retain the above copyright
  12.  *    notice, this list of conditions and the following disclaimer.
  13.  * 2. Redistributions in binary form must reproduce the above copyright
  14.  *    notice, this list of conditions and the following disclaimer in the
  15.  *    documentation and/or other materials provided with the distribution.
  16.  * 3. All advertising materials mentioning features or use of this software
  17.  *    must display the following acknowledgement:
  18.  *    This product includes software developed by the University of
  19.  *    California, Berkeley and its contributors.
  20.  * 4. Neither the name of the University nor the names of its contributors
  21.  *    may be used to endorse or promote products derived from this software
  22.  *    without specific prior written permission.
  23.  *
  24.  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
  25.  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  26.  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  27.  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
  28.  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  29.  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
  30.  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  31.  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  32.  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  33.  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  34.  * SUCH DAMAGE.
  35.  */
  36.  
  37. #if defined(LIBC_SCCS) && !defined(lint)
  38. static char sccsid[] = "@(#)vfprintf.c    5.47 (Berkeley) 3/22/91";
  39. #endif /* LIBC_SCCS and not lint */
  40.  
  41. /*
  42.  * Actual printf innards.
  43.  *
  44.  * This code is large and complicated...
  45.  */
  46.  
  47. #define KERNEL
  48. #include "ixemul.h"
  49.  
  50. #include <math.h>
  51. #include <stdio.h>
  52. #include <string.h>
  53. #if __STDC__
  54. #include <stdarg.h>
  55. #else
  56. #include <varargs.h>
  57. #endif
  58. #include "local.h"
  59. #include "fvwrite.h"
  60.  
  61. /*
  62.  * Define FLOATING_POINT to get floating point.
  63.  * Define CSH to get a csh-specific version (grr).
  64.  */
  65. #ifndef CSH
  66. #define    FLOATING_POINT
  67. #endif
  68.  
  69. /* end of configuration stuff */
  70.  
  71.  
  72. #ifdef CSH
  73. /*
  74.  * C shell hacks.  Ick, gag.
  75.  */
  76. #undef BUFSIZ
  77. #include "sh.h"
  78.  
  79. #if __STDC__
  80. int
  81. printf(const char *fmt, ...) {
  82.     FILE f;
  83.     va_list ap;
  84.     int ret;
  85.  
  86.     va_start(ap, fmt);
  87.     f._flags = __SWR;
  88.     f._write = NULL;
  89.     ret = vfprintf(&f, fmt, ap);
  90.     va_end(ap);
  91.     return ret;
  92. }
  93. #else
  94. int
  95. printf(fmt, args)
  96.     char *fmt;
  97. {
  98.     FILE f;
  99.  
  100.     f._flags = __SWR;
  101.     f._write = NULL;
  102.     return (vfprintf(&f, fmt, &args));
  103. }
  104. #endif
  105.  
  106. int
  107. __sprint(fp, uio)
  108.     FILE *fp;
  109.     register struct __suio *uio;
  110. {
  111.     register char *p;
  112.     register int n, ch, iovcnt;
  113.     register struct __siov *iov;
  114.  
  115.     /* must allow sprintf to work, might as well allow others too */
  116.     if (fp->_write || fp->_flags & __SSTR) {
  117.         if (uio->uio_resid == 0) {
  118.             uio->uio_iovcnt = 0;
  119.             return (0);
  120.         }
  121.         n = __sfvwrite(fp, uio);
  122.         uio->uio_resid = 0;
  123.         uio->uio_iovcnt = 0;
  124.         return (n);
  125.     }
  126.     iov = uio->uio_iov;
  127.     for (iovcnt = uio->uio_iovcnt; --iovcnt >= 0; iov++) {
  128.         for (p = iov->iov_base, n = iov->iov_len; --n >= 0;) {
  129. #ifdef CSHPUTCHAR
  130.             ch = *p++;
  131.             CSHPUTCHAR;    /* this horrid macro uses `ch' */
  132. #else
  133. #undef putchar
  134.             putchar(*p++);
  135. #endif
  136.         }
  137.     }
  138.     uio->uio_resid = 0;
  139.     uio->uio_iovcnt = 0;
  140.     return (0);
  141. }
  142.  
  143. #else /* CSH */
  144.  
  145. /*
  146.  * Flush out all the vectors defined by the given uio,
  147.  * then reset it so that it can be reused.
  148.  */
  149. static int
  150. __sprint(fp, uio)
  151.     FILE *fp;
  152.     register struct __suio *uio;
  153. {
  154.     register int err;
  155.  
  156.     if (uio->uio_resid == 0) {
  157.         uio->uio_iovcnt = 0;
  158.         return (0);
  159.     }
  160.     err = __sfvwrite(fp, uio);
  161.     uio->uio_resid = 0;
  162.     uio->uio_iovcnt = 0;
  163.     return (err);
  164. }
  165.  
  166. /*
  167.  * Helper function for `fprintf to unbuffered unix file': creates a
  168.  * temporary buffer.  We only work on write-only files; this avoids
  169.  * worries about ungetc buffers and so forth.
  170.  */
  171. static int
  172. __sbprintf(fp, fmt, ap)
  173.     register FILE *fp;
  174.     const char *fmt;
  175.     va_list ap;
  176. {
  177.     int ret;
  178.     FILE fake;
  179.     unsigned char buf[BUFSIZ];
  180.  
  181.     /* copy the important variables */
  182.     fake._flags = fp->_flags & ~__SNBF;
  183.     fake._file = fp->_file;
  184.     fake._cookie = fp->_cookie;
  185.     fake._write = fp->_write;
  186.  
  187.     /* set up the buffer */
  188.     fake._bf._base = fake._p = buf;
  189.     fake._bf._size = fake._w = sizeof(buf);
  190.     fake._lbfsize = 0;    /* not actually used, but Just In Case */
  191.  
  192.     /* do the work, then copy any error status */
  193.     ret = vfprintf(&fake, fmt, ap);
  194.     if (ret >= 0 && fflush(&fake))
  195.         ret = EOF;
  196.     if (fake._flags & __SERR)
  197.         fp->_flags |= __SERR;
  198.     return (ret);
  199. }
  200.  
  201. #endif /* CSH */
  202.  
  203.  
  204. #ifdef FLOATING_POINT
  205. #include "floatio.h"
  206.  
  207. #define    BUF        (MAXEXP+MAXFRACT+1)    /* + decimal point */
  208. #define    DEFPREC        6
  209.  
  210. static int cvt();
  211.  
  212. #else /* no FLOATING_POINT */
  213.  
  214. #define    BUF        40
  215.  
  216. #endif /* FLOATING_POINT */
  217.  
  218.  
  219. /*
  220.  * Macros for converting digits to letters and vice versa
  221.  */
  222. #define    to_digit(c)    ((c) - '0')
  223. #define is_digit(c)    ((unsigned)to_digit(c) <= 9)
  224. #define    to_char(n)    ((n) + '0')
  225.  
  226. /*
  227.  * Flags used during conversion.
  228.  */
  229. #undef LONGINT                /* in <intuition/iobsolete.h> */
  230. #define    LONGINT        0x01        /* long integer */
  231. #define    LONGDBL        0x02        /* long double; unimplemented */
  232. #define    SHORTINT    0x04        /* short integer */
  233. #define    ALT        0x08        /* alternate form */
  234. #define    LADJUST        0x10        /* left adjustment */
  235. #define    ZEROPAD        0x20        /* zero (as opposed to blank) pad */
  236. #define    HEXPREFIX    0x40        /* add 0x or 0X prefix */
  237.  
  238. int
  239. vfprintf(fp, fmt0, ap)
  240.     FILE *fp;
  241.     const char *fmt0;
  242. #if tahoe
  243.  register /* technically illegal, since we do not know what type va_list is */
  244. #endif
  245.     _VA_LIST_ ap;
  246. {
  247.     register char *fmt;    /* format string */
  248.     register int ch;    /* character from fmt */
  249.     register int n;        /* handy integer (short term usage) */
  250.     register char *cp;    /* handy char pointer (short term usage) */
  251.     register struct __siov *iovp;/* for PRINT macro */
  252.     register int flags;    /* flags as above */
  253.     int ret;        /* return value accumulator */
  254.     int width;        /* width from format (%8d), or 0 */
  255.     int prec;        /* precision from format (%.3d), or -1 */
  256.     char sign;        /* sign prefix (' ', '+', '-', or \0) */
  257. #ifdef FLOATING_POINT
  258.     char softsign;        /* temporary negative sign for floats */
  259.     double _double;        /* double precision arguments %[eEfgG] */
  260.     int fpprec;        /* `extra' floating precision in [eEfgG] */
  261. #endif
  262.     u_long _ulong;        /* integer arguments %[diouxX] */
  263.     enum { OCT, DEC, HEX } base;/* base for [diouxX] conversion */
  264.     int dprec;        /* a copy of prec if [diouxX], 0 otherwise */
  265.     int fieldsz;        /* field size expanded by sign, etc */
  266.     int realsz;        /* field size expanded by dprec */
  267.     int size;        /* size of converted field or string */
  268.     char *xdigs;        /* digits for [xX] conversion */
  269. #define NIOV 8
  270.     struct __suio uio;    /* output information: summary */
  271.     struct __siov iov[NIOV];/* ... and individual io vectors */
  272.     char buf[BUF];        /* space for %c, %[diouxX], %[eEfgG] */
  273.     char ox[2];        /* space for 0x hex-prefix */
  274.  
  275.     /*
  276.      * Choose PADSIZE to trade efficiency vs size.  If larger
  277.      * printf fields occur frequently, increase PADSIZE (and make
  278.      * the initialisers below longer).
  279.      */
  280. #define    PADSIZE    16        /* pad chunk size */
  281.     static char blanks[PADSIZE] =
  282.      {' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' '};
  283.     static char zeroes[PADSIZE] =
  284.      {'0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0'};
  285.  
  286.     /*
  287.      * BEWARE, these `goto error' on error, and PAD uses `n'.
  288.      */
  289. #define    PRINT(ptr, len) { \
  290.     iovp->iov_base = (ptr); \
  291.     iovp->iov_len = (len); \
  292.     uio.uio_resid += (len); \
  293.     iovp++; \
  294.     if (++uio.uio_iovcnt >= NIOV) { \
  295.         if (__sprint(fp, &uio)) \
  296.             goto error; \
  297.         iovp = iov; \
  298.     } \
  299. }
  300. #define    PAD(howmany, with) { \
  301.     if ((n = (howmany)) > 0) { \
  302.         while (n > PADSIZE) { \
  303.             PRINT(with, PADSIZE); \
  304.             n -= PADSIZE; \
  305.         } \
  306.         PRINT(with, n); \
  307.     } \
  308. }
  309. #define    FLUSH() { \
  310.     if (uio.uio_resid && __sprint(fp, &uio)) \
  311.         goto error; \
  312.     uio.uio_iovcnt = 0; \
  313.     iovp = iov; \
  314. }
  315.  
  316.     /*
  317.      * To extend shorts properly, we need both signed and unsigned
  318.      * argument extraction methods.
  319.      */
  320. #define    SARG() \
  321.     (flags&LONGINT ? va_arg(ap, long) : \
  322.         flags&SHORTINT ? (long)(short)va_arg(ap, int) : \
  323.         (long)va_arg(ap, int))
  324. #define    UARG() \
  325.     (flags&LONGINT ? va_arg(ap, u_long) : \
  326.         flags&SHORTINT ? (u_long)(u_short)va_arg(ap, int) : \
  327.         (u_long)va_arg(ap, u_int))
  328.  
  329. #ifndef CSH
  330.     /* sorry, fprintf(read_only_file, "") returns EOF, not 0 */
  331.     if (!fp || cantwrite(fp))
  332.         return (EOF);
  333.  
  334.     /* optimise fprintf(stderr) (and other unbuffered Unix files) */
  335.     if ((fp->_flags & (__SNBF|__SWR|__SRW)) == (__SNBF|__SWR) &&
  336.         fp->_file >= 0)
  337.         return (__sbprintf(fp, fmt0, ap));
  338. #endif /* CSH */
  339.  
  340.     fmt = (char *)fmt0;
  341.     uio.uio_iov = iovp = iov;
  342.     uio.uio_resid = 0;
  343.     uio.uio_iovcnt = 0;
  344.     ret = 0;
  345.  
  346.     /*
  347.      * Scan the format for conversions (`%' character).
  348.      */
  349.     for (;;) {
  350.         for (cp = fmt; (ch = *fmt) != '\0' && ch != '%'; fmt++)
  351.             /* void */;
  352.         if ((n = fmt - cp) != 0) {
  353.             PRINT(cp, n);
  354.             ret += n;
  355.         }
  356.         if (ch == '\0')
  357.             goto done;
  358.         fmt++;        /* skip over '%' */
  359.  
  360.         flags = 0;
  361.         dprec = 0;
  362. #ifdef FLOATING_POINT
  363.         fpprec = 0;
  364. #endif
  365.         width = 0;
  366.         prec = -1;
  367.         sign = '\0';
  368.  
  369. rflag:        ch = *fmt++;
  370. reswitch:    switch (ch) {
  371.         case ' ':
  372.             /*
  373.              * ``If the space and + flags both appear, the space
  374.              * flag will be ignored.''
  375.              *    -- ANSI X3J11
  376.              */
  377.             if (!sign)
  378.                 sign = ' ';
  379.             goto rflag;
  380.         case '#':
  381.             flags |= ALT;
  382.             goto rflag;
  383.         case '*':
  384.             /*
  385.              * ``A negative field width argument is taken as a
  386.              * - flag followed by a positive field width.''
  387.              *    -- ANSI X3J11
  388.              * They don't exclude field widths read from args.
  389.              */
  390.             if ((width = va_arg(ap, int)) >= 0)
  391.                 goto rflag;
  392.             width = -width;
  393.             /* FALLTHROUGH */
  394.         case '-':
  395.             flags |= LADJUST;
  396.             goto rflag;
  397.         case '+':
  398.             sign = '+';
  399.             goto rflag;
  400.         case '.':
  401.             if ((ch = *fmt++) == '*') {
  402.                 n = va_arg(ap, int);
  403.                 prec = n < 0 ? -1 : n;
  404.                 goto rflag;
  405.             }
  406.             n = 0;
  407.             while (is_digit(ch)) {
  408.                 n = 10 * n + to_digit(ch);
  409.                 ch = *fmt++;
  410.             }
  411.             prec = n < 0 ? -1 : n;
  412.             goto reswitch;
  413.         case '0':
  414.             /*
  415.              * ``Note that 0 is taken as a flag, not as the
  416.              * beginning of a field width.''
  417.              *    -- ANSI X3J11
  418.              */
  419.             flags |= ZEROPAD;
  420.             goto rflag;
  421.         case '1': case '2': case '3': case '4':
  422.         case '5': case '6': case '7': case '8': case '9':
  423.             n = 0;
  424.             do {
  425.                 n = 10 * n + to_digit(ch);
  426.                 ch = *fmt++;
  427.             } while (is_digit(ch));
  428.             width = n;
  429.             goto reswitch;
  430. #ifdef FLOATING_POINT
  431.         case 'L':
  432.             flags |= LONGDBL;
  433.             goto rflag;
  434. #endif
  435.         case 'h':
  436.             flags |= SHORTINT;
  437.             goto rflag;
  438.         case 'l':
  439.             flags |= LONGINT;
  440.             goto rflag;
  441.         case 'c':
  442.             *(cp = buf) = va_arg(ap, int);
  443.             size = 1;
  444.             sign = '\0';
  445.             break;
  446.         case 'D':
  447.             flags |= LONGINT;
  448.             /*FALLTHROUGH*/
  449.         case 'd':
  450.         case 'i':
  451.             _ulong = SARG();
  452.             if ((long)_ulong < 0) {
  453.                 _ulong = -_ulong;
  454.                 sign = '-';
  455.             }
  456.             base = DEC;
  457.             goto number;
  458. #ifdef FLOATING_POINT
  459.         case 'e':
  460.         case 'E':
  461.         case 'f':
  462.         case 'g':
  463.         case 'G':
  464.             _double = va_arg(ap, double);
  465.             /* do this before tricky precision changes */
  466.             if (isinf(_double)) {
  467.                 if (_double < 0)
  468.                     sign = '-';
  469.                 cp = "Inf";
  470.                 size = 3;
  471.                 break;
  472.             }
  473.             if (isnan(_double)) {
  474.                 cp = "NaN";
  475.                 size = 3;
  476.                 break;
  477.             }
  478.             /*
  479.              * don't do unrealistic precision; just pad it with
  480.              * zeroes later, so buffer size stays rational.
  481.              */
  482.             if (prec > MAXFRACT) {
  483.                 if (ch != 'g' && ch != 'G' || (flags&ALT))
  484.                     fpprec = prec - MAXFRACT;
  485.                 prec = MAXFRACT;
  486.             } else if (prec == -1)
  487.                 prec = DEFPREC;
  488.             /*
  489.              * cvt may have to round up before the "start" of
  490.              * its buffer, i.e. ``intf("%.2f", (double)9.999);'';
  491.              * if the first character is still NUL, it did.
  492.              * softsign avoids negative 0 if _double < 0 but
  493.              * no significant digits will be shown.
  494.              */
  495.             cp = buf;
  496.             *cp = '\0';
  497.             size = cvt(_double, prec, flags, &softsign, ch,
  498.                 cp, buf + sizeof(buf));
  499.             if (softsign)
  500.                 sign = '-';
  501.             if (*cp == '\0')
  502.                 cp++;
  503.             break;
  504. #endif /* FLOATING_POINT */
  505.         case 'n':
  506.             if (flags & LONGINT)
  507.                 *va_arg(ap, long *) = ret;
  508.             else if (flags & SHORTINT)
  509.                 *va_arg(ap, short *) = ret;
  510.             else
  511.                 *va_arg(ap, int *) = ret;
  512.             continue;    /* no output */
  513.         case 'O':
  514.             flags |= LONGINT;
  515.             /*FALLTHROUGH*/
  516.         case 'o':
  517.             _ulong = UARG();
  518.             base = OCT;
  519.             goto nosign;
  520.         case 'p':
  521.             /*
  522.              * ``The argument shall be a pointer to void.  The
  523.              * value of the pointer is converted to a sequence
  524.              * of printable characters, in an implementation-
  525.              * defined manner.''
  526.              *    -- ANSI X3J11
  527.              */
  528.             /* NOSTRICT */
  529.             _ulong = (u_long)va_arg(ap, void *);
  530.             base = HEX;
  531.             xdigs = "0123456789abcdef";
  532.             flags |= HEXPREFIX;
  533.             ch = 'x';
  534.             goto nosign;
  535.         case 's':
  536.             if ((cp = va_arg(ap, char *)) == NULL)
  537.                 cp = "(null)";
  538.             if (prec >= 0) {
  539.                 /*
  540.                  * can't use strlen; can only look for the
  541.                  * NUL in the first `prec' characters, and
  542.                  * strlen() will go further.
  543.                  */
  544.                 char *p = memchr(cp, 0, prec);
  545.  
  546.                 if (p != NULL) {
  547.                     size = p - cp;
  548.                     if (size > prec)
  549.                         size = prec;
  550.                 } else
  551.                     size = prec;
  552.             } else
  553.                 size = strlen(cp);
  554.             sign = '\0';
  555.             break;
  556.         case 'U':
  557.             flags |= LONGINT;
  558.             /*FALLTHROUGH*/
  559.         case 'u':
  560.             _ulong = UARG();
  561.             base = DEC;
  562.             goto nosign;
  563.         case 'X':
  564.             xdigs = "0123456789ABCDEF";
  565.             goto hex;
  566.         case 'x':
  567.             xdigs = "0123456789abcdef";
  568. hex:            _ulong = UARG();
  569.             base = HEX;
  570.             /* leading 0x/X only if non-zero */
  571.             if (flags & ALT && _ulong != 0)
  572.                 flags |= HEXPREFIX;
  573.  
  574.             /* unsigned conversions */
  575. nosign:            sign = '\0';
  576.             /*
  577.              * ``... diouXx conversions ... if a precision is
  578.              * specified, the 0 flag will be ignored.''
  579.              *    -- ANSI X3J11
  580.              */
  581. number:            if ((dprec = prec) >= 0)
  582.                 flags &= ~ZEROPAD;
  583.  
  584.             /*
  585.              * ``The result of converting a zero value with an
  586.              * explicit precision of zero is no characters.''
  587.              *    -- ANSI X3J11
  588.              */
  589.             cp = buf + BUF;
  590.             if (_ulong != 0 || prec != 0) {
  591.                 /*
  592.                  * unsigned mod is hard, and unsigned mod
  593.                  * by a constant is easier than that by
  594.                  * a variable; hence this switch.
  595.                  */
  596.                 switch (base) {
  597.                 case OCT:
  598.                     do {
  599.                         *--cp = to_char(_ulong & 7);
  600.                         _ulong >>= 3;
  601.                     } while (_ulong);
  602.                     /* handle octal leading 0 */
  603.                     if (flags & ALT && *cp != '0')
  604.                         *--cp = '0';
  605.                     break;
  606.  
  607.                 case DEC:
  608.                     /* many numbers are 1 digit */
  609.                     while (_ulong >= 10) {
  610.                         *--cp = to_char(_ulong % 10);
  611.                         _ulong /= 10;
  612.                     }
  613.                     *--cp = to_char(_ulong);
  614.                     break;
  615.  
  616.                 case HEX:
  617.                     do {
  618.                         *--cp = xdigs[_ulong & 15];
  619.                         _ulong >>= 4;
  620.                     } while (_ulong);
  621.                     break;
  622.  
  623.                 default:
  624.                     cp = "bug in vfprintf: bad base";
  625.                     size = strlen(cp);
  626.                     goto skipsize;
  627.                 }
  628.             }
  629.             size = buf + BUF - cp;
  630.         skipsize:
  631.             break;
  632.         default:    /* "%?" prints ?, unless ? is NUL */
  633.             if (ch == '\0')
  634.                 goto done;
  635.             /* pretend it was %c with argument ch */
  636.             cp = buf;
  637.             *cp = ch;
  638.             size = 1;
  639.             sign = '\0';
  640.             break;
  641.         }
  642.  
  643.         /*
  644.          * All reasonable formats wind up here.  At this point,
  645.          * `cp' points to a string which (if not flags&LADJUST)
  646.          * should be padded out to `width' places.  If
  647.          * flags&ZEROPAD, it should first be prefixed by any
  648.          * sign or other prefix; otherwise, it should be blank
  649.          * padded before the prefix is emitted.  After any
  650.          * left-hand padding and prefixing, emit zeroes
  651.          * required by a decimal [diouxX] precision, then print
  652.          * the string proper, then emit zeroes required by any
  653.          * leftover floating precision; finally, if LADJUST,
  654.          * pad with blanks.
  655.          */
  656.  
  657.         /*
  658.          * compute actual size, so we know how much to pad.
  659.          * fieldsz excludes decimal prec; realsz includes it
  660.          */
  661. #ifdef FLOATING_POINT
  662.         fieldsz = size + fpprec;
  663. #else
  664.         fieldsz = size;
  665. #endif
  666.         if (sign)
  667.             fieldsz++;
  668.         else if (flags & HEXPREFIX)
  669.             fieldsz += 2;
  670.         realsz = dprec > fieldsz ? dprec : fieldsz;
  671.  
  672.         /* right-adjusting blank padding */
  673.         if ((flags & (LADJUST|ZEROPAD)) == 0)
  674.             PAD(width - realsz, blanks);
  675.  
  676.         /* prefix */
  677.         if (sign) {
  678.             PRINT(&sign, 1);
  679.         } else if (flags & HEXPREFIX) {
  680.             ox[0] = '0';
  681.             ox[1] = ch;
  682.             PRINT(ox, 2);
  683.         }
  684.  
  685.         /* right-adjusting zero padding */
  686.         if ((flags & (LADJUST|ZEROPAD)) == ZEROPAD)
  687.             PAD(width - realsz, zeroes);
  688.  
  689.         /* leading zeroes from decimal precision */
  690.         PAD(dprec - fieldsz, zeroes);
  691.  
  692.         /* the string or number proper */
  693.         PRINT(cp, size);
  694.  
  695. #ifdef FLOATING_POINT
  696.         /* trailing f.p. zeroes */
  697.         PAD(fpprec, zeroes);
  698. #endif
  699.  
  700.         /* left-adjusting padding (always blank) */
  701.         if (flags & LADJUST)
  702.             PAD(width - realsz, blanks);
  703.  
  704.         /* finally, adjust ret */
  705.         ret += width > realsz ? width : realsz;
  706.  
  707.         FLUSH();    /* copy out the I/O vectors */
  708.     }
  709. done:
  710.     FLUSH();
  711. error:
  712.     return (__sferror(fp) ? EOF : ret);
  713.     /* NOTREACHED */
  714. }
  715.  
  716. #ifdef FLOATING_POINT
  717. #include <math.h>
  718.  
  719. static char *exponent();
  720. static char *round();
  721.  
  722. static int
  723. cvt(number, prec, flags, signp, fmtch, startp, endp)
  724.     double number;
  725.     register int prec;
  726.     int flags;
  727.     char *signp;
  728.     int fmtch;
  729.     char *startp, *endp;
  730. {
  731.     register char *p, *t;
  732.     register double fract;
  733.     int dotrim, expcnt, gformat, add_1_to_exp = 1;
  734.     double integer, tmp;
  735.  
  736.     dotrim = expcnt = gformat = 0;
  737.     if (number < 0) {
  738.         number = -number;
  739.         *signp = '-';
  740.     } else
  741.         *signp = 0;
  742.  
  743.     fract = modf(number, &integer);
  744.  
  745.     /* get an extra slot for rounding. */
  746.     t = ++startp;
  747.  
  748.     /*
  749.      * get integer portion of number; put into the end of the buffer; the
  750.      * .01 is added for modf(356.0 / 10, &integer) returning .59999999...
  751.      */
  752.     for (p = endp - 1; integer; ++expcnt) {
  753.         tmp = modf(integer / 10, &integer);
  754.         *p = to_char((int)((tmp + .01) * 10));
  755.         if (*p-- != '9')
  756.           add_1_to_exp = 0;
  757.     }
  758.     if (add_1_to_exp && fract < 0.5)
  759.       add_1_to_exp = 0;
  760.       
  761.     switch (fmtch) {
  762.     case 'f':
  763.         /* reverse integer into beginning of buffer */
  764.         if (expcnt)
  765.             for (; ++p < endp; *t++ = *p);
  766.         else
  767.             *t++ = '0';
  768.         /*
  769.          * if precision required or alternate flag set, add in a
  770.          * decimal point.
  771.          */
  772.         if (prec || flags&ALT)
  773.             *t++ = '.';
  774.         /* if requires more precision and some fraction left */
  775.         if (fract) {
  776.             if (prec)
  777.                 do {
  778.                     fract = modf(fract * 10, &tmp);
  779.                     *t++ = to_char((int)tmp);
  780.                 } while (--prec && fract);
  781.             if (fract)
  782.                 startp = round(fract, (int *)NULL, startp,
  783.                     t - 1, (char)0, signp);
  784.         }
  785.         for (; prec--; *t++ = '0');
  786.         break;
  787.     case 'e':
  788.     case 'E':
  789. eformat:    if (expcnt) {
  790.             *t++ = *++p;
  791.             if (prec || flags&ALT)
  792.                 *t++ = '.';
  793.             /* if requires more precision and some integer left */
  794.             for (; prec && ++p < endp; --prec)
  795.                 *t++ = *p;
  796.             /*
  797.              * if done precision and more of the integer component,
  798.              * round using it; adjust fract so we don't re-round
  799.              * later.
  800.              */
  801.             if (!prec && ++p < endp) {
  802.                 fract = 0;
  803.                 startp = round((double)0, &expcnt, startp,
  804.                     t - 1, *p, signp);
  805.             }
  806.             /* adjust expcnt for digit in front of decimal */
  807.             --expcnt;
  808.         }
  809.         /* until first fractional digit, decrement exponent */
  810.         else if (fract) {
  811.             /* adjust expcnt for digit in front of decimal */
  812.             for (expcnt = -1;; --expcnt) {
  813.                 fract = modf(fract * 10, &tmp);
  814.                 if (tmp)
  815.                     break;
  816.             }
  817.             *t++ = to_char((int)tmp);
  818.             if (prec || flags&ALT)
  819.                 *t++ = '.';
  820.         }
  821.         else {
  822.             *t++ = '0';
  823.             if (prec || flags&ALT)
  824.                 *t++ = '.';
  825.         }
  826.         /* if requires more precision and some fraction left */
  827.         if (fract) {
  828.             if (prec)
  829.                 do {
  830.                     fract = modf(fract * 10, &tmp);
  831.                     *t++ = to_char((int)tmp);
  832.                 } while (--prec && fract);
  833.             if (fract)
  834.                 startp = round(fract, &expcnt, startp,
  835.                     t - 1, (char)0, signp);
  836.         }
  837.         /* if requires more precision */
  838.         for (; prec--; *t++ = '0');
  839.  
  840.         /* unless alternate flag, trim any g/G format trailing 0's */
  841.         if (gformat && !(flags&ALT)) {
  842.             while (t > startp && *--t == '0');
  843.             if (*t == '.')
  844.                 --t;
  845.             ++t;
  846.         }
  847.         t = exponent(t, expcnt, fmtch);
  848.         break;
  849.     case 'g':
  850.     case 'G':
  851.         /* a precision of 0 is treated as a precision of 1. */
  852.         if (!prec)
  853.             ++prec;
  854.         /*
  855.          * ``The style used depends on the value converted; style e
  856.          * will be used only if the exponent resulting from the
  857.          * conversion is less than -4 or greater or equal than the
  858.                  * precision.''
  859.          *    -- ANSI X3J11
  860.          */
  861.         if (expcnt + add_1_to_exp > prec || !expcnt && fract && fract < .0001) {
  862.             /*
  863.              * g/G format counts "significant digits, not digits of
  864.              * precision; for the e/E format, this just causes an
  865.              * off-by-one problem, i.e. g/G considers the digit
  866.              * before the decimal point significant and e/E doesn't
  867.              * count it as precision.
  868.              */
  869.             --prec;
  870.             fmtch -= 2;        /* G->E, g->e */
  871.             gformat = 1;
  872.             goto eformat;
  873.         }
  874.         /*
  875.          * reverse integer into beginning of buffer,
  876.          * note, decrement precision
  877.          */
  878.         if (expcnt)
  879.             for (; ++p < endp; *t++ = *p, --prec);
  880.         else
  881.             *t++ = '0';
  882.         /*
  883.          * if precision required or alternate flag set, add in a
  884.          * decimal point.  If no digits yet, add in leading 0.
  885.          */
  886.         if (prec || flags&ALT) {
  887.             dotrim = 1;
  888.             *t++ = '.';
  889.         }
  890.         else
  891.             dotrim = 0;
  892.         /* if requires more precision and some fraction left */
  893.         if (fract) {
  894.             if (prec) {
  895.                 do {
  896.                     fract = modf(fract * 10, &tmp);
  897.                     *t++ = to_char((int)tmp);
  898.                 } while(!tmp);
  899.                 while (--prec && fract) {
  900.                     fract = modf(fract * 10, &tmp);
  901.                     *t++ = to_char((int)tmp);
  902.                 }
  903.             }
  904.             if (fract)
  905.                 startp = round(fract, (int *)NULL, startp,
  906.                     t - 1, (char)0, signp);
  907.         }
  908.         /* alternate format, adds 0's for precision, else trim 0's */
  909.         if (flags&ALT)
  910.             for (; prec--; *t++ = '0');
  911.         else if (dotrim) {
  912.             while (t > startp && *--t == '0');
  913.             if (*t != '.')
  914.                 ++t;
  915.         }
  916.     }
  917.     return (t - startp);
  918. }
  919.  
  920. static char *
  921. round(fract, exp, start, end, ch, signp)
  922.     double fract;
  923.     int *exp;
  924.     register char *start, *end;
  925.     char ch, *signp;
  926. {
  927.     double tmp;
  928.  
  929.     if (fract)
  930.         (void)modf(fract * 10, &tmp);
  931.     else
  932.         tmp = to_digit(ch);
  933.     if (tmp > 4)
  934.         for (;; --end) {
  935.             if (*end == '.')
  936.                 --end;
  937.             if (++*end <= '9')
  938.                 break;
  939.             *end = '0';
  940.             if (end == start) {
  941.                 if (exp) {    /* e/E; increment exponent */
  942.                     *end = '1';
  943.                     ++*exp;
  944.                 }
  945.                 else {        /* f; add extra digit */
  946.                 *--end = '1';
  947.                 --start;
  948.                 }
  949.                 break;
  950.             }
  951.         }
  952.     /* ``"%.3f", (double)-0.0004'' gives you a negative 0. */
  953.     else if (*signp == '-')
  954.         for (;; --end) {
  955.             if (*end == '.')
  956.                 --end;
  957.             if (*end != '0')
  958.                 break;
  959.             if (end == start)
  960.                 *signp = 0;
  961.         }
  962.     return (start);
  963. }
  964.  
  965. static char *
  966. exponent(p, exp, fmtch)
  967.     register char *p;
  968.     register int exp;
  969.     int fmtch;
  970. {
  971.     register char *t;
  972.     char expbuf[MAXEXP];
  973.  
  974.     *p++ = fmtch;
  975.     if (exp < 0) {
  976.         exp = -exp;
  977.         *p++ = '-';
  978.     }
  979.     else
  980.         *p++ = '+';
  981.     t = expbuf + MAXEXP;
  982.     if (exp > 9) {
  983.         do {
  984.             *--t = to_char(exp % 10);
  985.         } while ((exp /= 10) > 9);
  986.         *--t = to_char(exp);
  987.         for (; t < expbuf + MAXEXP; *p++ = *t++);
  988.     }
  989.     else {
  990.         *p++ = '0';
  991.         *p++ = to_char(exp);
  992.     }
  993.     return (p);
  994. }
  995. #endif /* FLOATING_POINT */
  996.